/**
 * TinyMCE version 7.7.1 (2025-03-05)
 */

(function() {
  "use strict";

  const Cell = initial => {
    let value = initial;
    const get = () => {
      return value;
    };
    const set = v => {
      value = v;
    };
    return {
      get,
      set
    };
  };

  var global = tinymce.util.Tools.resolve("tinymce.PluginManager");

  const get$2 = toggleState => {
    const isEnabled = () => {
      return toggleState.get();
    };
    return { isEnabled };
  };

  const fireVisualChars = (editor, state) => {
    return editor.dispatch("VisualChars", { state });
  };

  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = x => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType$1 = type => value => typeOf(value) === type;
  const isSimpleType = type => value => typeof value === type;
  const eq = t => a => t === a;
  const isString = isType$1("string");
  const isObject = isType$1("object");
  const isNull = eq(null);
  const isBoolean = isSimpleType("boolean");
  const isNullable = a => a === null || a === undefined;
  const isNonNullable = a => !isNullable(a);
  const isNumber = isSimpleType("number");

  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }

    static some(value) {
      return new Optional(true, value);
    }

    static none() {
      return Optional.singletonNone;
    }

    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }

    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }

    isSome() {
      return this.tag;
    }

    isNone() {
      return !this.tag;
    }

    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }

    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }

    exists(predicate) {
      return this.tag && predicate(this.value);
    }

    forall(predicate) {
      return !this.tag || predicate(this.value);
    }

    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }

    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }

    or(replacement) {
      return this.tag ? this : replacement;
    }

    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }

    orThunk(thunk) {
      return this.tag ? this : thunk();
    }

    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }

    getOrNull() {
      return this.tag ? this.value : null;
    }

    getOrUndefined() {
      return this.value;
    }

    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }

    toArray() {
      return this.tag ? [this.value] : [];
    }

    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }

  Optional.singletonNone = new Optional(false);

  const map = (xs, f) => {
    const len = xs.length;
    const r = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r[i] = f(x, i);
    }
    return r;
  };
  const each$1 = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const filter = (xs, pred) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        r.push(x);
      }
    }
    return r;
  };

  const keys = Object.keys;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };

  const Global = typeof window !== "undefined" ? window : Function("return this;")();

  const path = (parts, scope) => {
    let o = scope !== undefined && scope !== null ? scope : Global;
    for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
      o = o[parts[i]];
    }
    return o;
  };
  const resolve = (p, scope) => {
    const parts = p.split(".");
    return path(parts, scope);
  };

  const unsafe = (name, scope) => {
    return resolve(name, scope);
  };
  const getOrDie = (name, scope) => {
    const actual = unsafe(name, scope);
    if (actual === undefined || actual === null) {
      throw new Error(name + " not available on this browser");
    }
    return actual;
  };

  const getPrototypeOf = Object.getPrototypeOf;
  const sandHTMLElement = scope => {
    return getOrDie("HTMLElement", scope);
  };
  const isPrototypeOf = x => {
    const scope = resolve("ownerDocument.defaultView", x);
    return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf(x).constructor.name));
  };

  const ELEMENT = 1;
  const TEXT = 3;

  const type = element => element.dom.nodeType;
  const value = element => element.dom.nodeValue;
  const isType = t => element => type(element) === t;
  const isHTMLElement = element => isElement(element) && isPrototypeOf(element.dom);
  const isElement = isType(ELEMENT);
  const isText = isType(TEXT);

  const rawSet = (dom, key, value) => {
    if (isString(value) || isBoolean(value) || isNumber(value)) {
      dom.setAttribute(key, value + "");
    } else {
      console.error("Invalid call to Attribute.set. Key ", key, ":: Value ", value, ":: Element ", dom);
      throw new Error("Attribute value was not simple");
    }
  };
  const set = (element, key, value) => {
    rawSet(element.dom, key, value);
  };
  const get$1 = (element, key) => {
    const v = element.dom.getAttribute(key);
    return v === null ? undefined : v;
  };
  const remove$3 = (element, key) => {
    element.dom.removeAttribute(key);
  };

  const read = (element, attr) => {
    const value = get$1(element, attr);
    return value === undefined || value === "" ? [] : value.split(" ");
  };
  const add$2 = (element, attr, id) => {
    const old = read(element, attr);
    const nu = old.concat([id]);
    set(element, attr, nu.join(" "));
    return true;
  };
  const remove$2 = (element, attr, id) => {
    const nu = filter(read(element, attr), v => v !== id);
    if (nu.length > 0) {
      set(element, attr, nu.join(" "));
    } else {
      remove$3(element, attr);
    }
    return false;
  };

  const supports = element => element.dom.classList !== undefined;
  const get = element => read(element, "class");
  const add$1 = (element, clazz) => add$2(element, "class", clazz);
  const remove$1 = (element, clazz) => remove$2(element, "class", clazz);

  const add = (element, clazz) => {
    if (supports(element)) {
      element.dom.classList.add(clazz);
    } else {
      add$1(element, clazz);
    }
  };
  const cleanClass = element => {
    const classList = supports(element) ? element.dom.classList : get(element);
    if (classList.length === 0) {
      remove$3(element, "class");
    }
  };
  const remove = (element, clazz) => {
    if (supports(element)) {
      const classList = element.dom.classList;
      classList.remove(clazz);
    } else {
      remove$1(element, clazz);
    }
    cleanClass(element);
  };

  const fromHtml = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      const message = "HTML does not have a single root node";
      console.error(message, html);
      throw new Error(message);
    }
    return fromDom(div.childNodes[0]);
  };
  const fromTag = (tag, scope) => {
    const doc = scope || document;
    const node = doc.createElement(tag);
    return fromDom(node);
  };
  const fromText = (text, scope) => {
    const doc = scope || document;
    const node = doc.createTextNode(text);
    return fromDom(node);
  };
  const fromDom = node => {
    if (node === null || node === undefined) {
      throw new Error("Node cannot be null or undefined");
    }
    return { dom: node };
  };
  const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  const SugarElement = {
    fromHtml,
    fromTag,
    fromText,
    fromDom,
    fromPoint
  };

  const charMap = {
    "\xA0": "nbsp",
    "\xAD": "shy"
  };
  const charMapToRegExp = (charMap, global) => {
    let regExp = "";
    each(charMap, (_value, key) => {
      regExp += key;
    });
    return new RegExp("[" + regExp + "]", global ? "g" : "");
  };
  const charMapToSelector = charMap => {
    let selector = "";
    each(charMap, value => {
      if (selector) {
        selector += ",";
      }
      selector += "span.mce-" + value;
    });
    return selector;
  };
  const regExp = charMapToRegExp(charMap);
  const regExpGlobal = charMapToRegExp(charMap, true);
  const selector = charMapToSelector(charMap);
  const nbspClass = "mce-nbsp";

  const getRaw = element => element.dom.contentEditable;

  const wrapCharWithSpan = value => "<span data-mce-bogus=\"1\" class=\"mce-" + charMap[value] + "\">" + value + "</span>";

  const isWrappedNbsp = node => node.nodeName.toLowerCase() === "span" && node.classList.contains("mce-nbsp-wrap");
  const isMatch = n => {
    const value$1 = value(n);
    return isText(n) && isString(value$1) && regExp.test(value$1);
  };
  const isContentEditableFalse = node => isHTMLElement(node) && getRaw(node) === "false";
  const isChildEditable = (node, currentState) => {
    if (isHTMLElement(node) && !isWrappedNbsp(node.dom)) {
      const value = getRaw(node);
      if (value === "true") {
        return true;
      } else if (value === "false") {
        return false;
      }
    }
    return currentState;
  };
  const filterEditableDescendants = (scope, predicate, editable) => {
    let result = [];
    const dom = scope.dom;
    const children = map(dom.childNodes, SugarElement.fromDom);
    const isEditable = node => isWrappedNbsp(node.dom) || !isContentEditableFalse(node);
    each$1(children, x => {
      if (editable && isEditable(x) && predicate(x)) {
        result = result.concat([x]);
      }
      result = result.concat(filterEditableDescendants(x, predicate, isChildEditable(x, editable)));
    });
    return result;
  };
  const findParentElm = (elm, rootElm) => {
    while (elm.parentNode) {
      if (elm.parentNode === rootElm) {
        return rootElm;
      }
      elm = elm.parentNode;
    }
    return undefined;
  };
  const replaceWithSpans = text => text.replace(regExpGlobal, wrapCharWithSpan);

  const show = (editor, rootElm) => {
    const dom = editor.dom;
    const nodeList = filterEditableDescendants(SugarElement.fromDom(rootElm), isMatch, editor.dom.isEditable(rootElm));
    each$1(nodeList, n => {
      var _a;
      const parent = n.dom.parentNode;
      if (isWrappedNbsp(parent)) {
        add(SugarElement.fromDom(parent), nbspClass);
      } else {
        const withSpans = replaceWithSpans(dom.encode((_a = value(n)) !== null && _a !== void 0 ? _a : ""));
        const div = dom.create("div", {}, withSpans);
        let node;
        while (node = div.lastChild) {
          dom.insertAfter(node, n.dom);
        }
        editor.dom.remove(n.dom);
      }
    });
  };
  const hide = (editor, rootElm) => {
    const nodeList = editor.dom.select(selector, rootElm);
    each$1(nodeList, node => {
      if (isWrappedNbsp(node)) {
        remove(SugarElement.fromDom(node), nbspClass);
      } else {
        editor.dom.remove(node, true);
      }
    });
  };
  const toggle = editor => {
    const body = editor.getBody();
    const bookmark = editor.selection.getBookmark();
    let parentNode = findParentElm(editor.selection.getNode(), body);
    parentNode = parentNode !== undefined ? parentNode : body;
    hide(editor, parentNode);
    show(editor, parentNode);
    editor.selection.moveToBookmark(bookmark);
  };

  const applyVisualChars = (editor, toggleState) => {
    fireVisualChars(editor, toggleState.get());
    const body = editor.getBody();
    if (toggleState.get() === true) {
      show(editor, body);
    } else {
      hide(editor, body);
    }
  };
  const toggleVisualChars = (editor, toggleState) => {
    toggleState.set(!toggleState.get());
    const bookmark = editor.selection.getBookmark();
    applyVisualChars(editor, toggleState);
    editor.selection.moveToBookmark(bookmark);
  };

  const register$2 = (editor, toggleState) => {
    editor.addCommand("mceVisualChars", () => {
      toggleVisualChars(editor, toggleState);
    });
  };

  const option = name => editor => editor.options.get(name);
  const register$1 = editor => {
    const registerOption = editor.options.register;
    registerOption("visualchars_default_state", {
      processor: "boolean",
      default: false
    });
  };
  const isEnabledByDefault = option("visualchars_default_state");

  const setup$1 = (editor, toggleState) => {
    editor.on("init", () => {
      applyVisualChars(editor, toggleState);
    });
  };

  const first = (fn, rate) => {
    let timer = null;
    const cancel = () => {
      if (!isNull(timer)) {
        clearTimeout(timer);
        timer = null;
      }
    };
    const throttle = (...args) => {
      if (isNull(timer)) {
        timer = setTimeout(() => {
          timer = null;
          fn.apply(null, args);
        }, rate);
      }
    };
    return {
      cancel,
      throttle
    };
  };

  const setup = (editor, toggleState) => {
    const debouncedToggle = first(() => {
      toggle(editor);
    }, 300);
    editor.on("keydown", e => {
      if (toggleState.get() === true) {
        e.keyCode === 13 ? toggle(editor) : debouncedToggle.throttle();
      }
    });
    editor.on("remove", debouncedToggle.cancel);
  };

  const toggleActiveState = (editor, enabledStated) => api => {
    api.setActive(enabledStated.get());
    const editorEventCallback = e => api.setActive(e.state);
    editor.on("VisualChars", editorEventCallback);
    return () => editor.off("VisualChars", editorEventCallback);
  };
  const register = (editor, toggleState) => {
    const onAction = () => editor.execCommand("mceVisualChars");
    editor.ui.registry.addToggleButton("visualchars", {
      tooltip: "Show invisible characters",
      icon: "visualchars",
      onAction,
      onSetup: toggleActiveState(editor, toggleState),
      context: "any"
    });
    editor.ui.registry.addToggleMenuItem("visualchars", {
      text: "Show invisible characters",
      icon: "visualchars",
      onAction,
      onSetup: toggleActiveState(editor, toggleState),
      context: "any"
    });
  };

  var Plugin = () => {
    global.add("visualchars", editor => {
      register$1(editor);
      const toggleState = Cell(isEnabledByDefault(editor));
      register$2(editor, toggleState);
      register(editor, toggleState);
      setup(editor, toggleState);
      setup$1(editor, toggleState);
      return get$2(toggleState);
    });
  };

  Plugin();

})();
